// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2023. All rights reserved.
 */

#include <linux/spinlock.h>
#include <linux/jiffies.h>
#include <linux/printk.h>

#include "ratelimit.h"

#ifdef CONFIG_EULEROS_ADD_RATELIMIT

/* Not more than 2 messages every 5 seconds */
static DEFINE_RATELIMIT_STATE(ratelimit_aer, 5*HZ, 2);

bool aer_ratelimit(bool log_start)
{
	unsigned long flags;
	int ret;

	if (!ratelimit_aer.interval)
		return 1;

	/*
	 * If we contend on this state's lock then almost
	 * by definition we are too busy to print a message,
	 * in addition to the one that will be printed by
	 * the entity that is holding the lock already:
	 */
	if (!raw_spin_trylock_irqsave(&ratelimit_aer.lock, flags))
		return 0;

	if (!ratelimit_aer.begin)
		ratelimit_aer.begin = jiffies;

	if (time_is_before_jiffies(ratelimit_aer.begin + ratelimit_aer.interval)) {
		if (ratelimit_aer.missed) {
			if (!(ratelimit_aer.flags & RATELIMIT_MSG_ON_RELEASE)) {
				printk_deferred("%s: %d callbacks suppressed\n",
						__func__, ratelimit_aer.missed);
				ratelimit_aer.missed = 0;
			}
		}
		ratelimit_aer.begin   = jiffies;
		ratelimit_aer.printed = 0;
	}
	if (ratelimit_aer.burst && log_start) {
		ratelimit_aer.printed++;
		if (ratelimit_aer.burst >= ratelimit_aer.printed) {
			/* The first log is in burst range */
			ret = 1;
		} else {
			/* The first log is out of  burst range, account miss times */
			ratelimit_aer.missed++;
			ret = 0;
		}
	} else if (ratelimit_aer.burst
			&& ratelimit_aer.burst >= ratelimit_aer.printed
			&& !log_start) {
		/* The remaining log is in burst range */
		ret = 1;
	} else {
		/* The remaining log is out of burst range */
		ret = 0;
	}
	raw_spin_unlock_irqrestore(&ratelimit_aer.lock, flags);

	return ret;
}
#endif
